# *_*coding:utf-8 *_*
# @Author : Reggie
# @Time : 2021/11/26 15:57
import json
import logging
import os
import shlex
import subprocess
from pathlib import Path

DiskSnPath = "/etc/uraid/conf/disk-sn/"
ENVIRON = {
    "OFMT": "JSON",
    "LANG": "en_US.UTF-8;"
}
LOG_LEVEL = "INFO"

env_debug = True if os.environ.get("DEBUG") else False
if env_debug:
    LOG_LEVEL = "DEBUG"

nolog = True if os.environ.get("nolog") else False
if not nolog:
    root_logger = logging.getLogger()
    stream_handle = logging.StreamHandler()
    formatter = logging.Formatter("%(asctime)s -- %(levelname)s --"
                                  " %(message)s (%(funcName)s in %(filename)s %(lineno)d)")
    stream_handle.setFormatter(formatter)
    root_logger.addHandler(stream_handle)
    root_logger.setLevel(LOG_LEVEL)


def run_command(cmd,
                shell=False,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                stdin=subprocess.PIPE,
                input=None,
                cmd_env=None,
                raise_error=False,
                json_out=False,
                encode="utf-8"):
    out, err, rc = {}, "", 1

    if shell:
        if isinstance(cmd, (list, tuple)):
            cmd = " ".join([str(i) for i in cmd])
    else:
        if isinstance(cmd, str):
            cmd = shlex.split(cmd)
        elif isinstance(cmd, (list, tuple)):
            cmd = [str(i) for i in cmd]
    cmd_str = " ".join(cmd) if isinstance(cmd, (list, tuple)) else cmd

    env = dict(os.environ)
    if cmd_env:
        for k in cmd_env.keys():
            env[k] = cmd_env[k]

    try:
        logging.debug(f"Running command: {cmd_str}")
        p = subprocess.Popen(args=cmd, shell=shell, stdout=stdout, stderr=stderr, stdin=stdin, env=env)
        out, err = p.communicate(input=input)
        rc = p.returncode
    except Exception as e:
        err = f"Run Command Error: {e}"
        if raise_error:
            raise Exception(e)
        return out, err, rc

    if encode:
        out = out.decode(encode)
        err = err.decode(encode)

    if json_out:
        try:
            out = json.loads(out)
        except Exception as e:
            err = f"JSON Loads Error: {e}"
            if raise_error:
                raise Exception(e)
            return out, err, rc

    return out, err, rc


def uus_node_links():
    out, err, rc = run_command("ucli node links", cmd_env=ENVIRON, json_out=True)
    if rc != 0:
        logging.error(f"out:{out} err:{err} rc:{rc}")
        return []
    return out.get("data")


def uus_disk_list():
    out, err, rc = run_command("ucli disk list all local", cmd_env=ENVIRON, json_out=True)
    if rc != 0:
        logging.error(f"out:{out} err:{err} rc:{rc}")
        return []
    return out.get("data")


def uus_disk_remove(disk_id):
    out, err, rc = run_command(f"ucli disk show {disk_id}", cmd_env=ENVIRON, json_out=True)
    logging.info(f"{out}")
    if rc != 0:
        logging.error(f"{disk_id} has been remove!")
        return
    out, err, rc = run_command(f"ucli disk remove {disk_id}", cmd_env=ENVIRON, json_out=True)
    if rc == 0:
        logging.info(f"remove disk ok! {disk_id}")
    else:
        logging.info(f"remove disk error! {disk_id}")
        logging.debug(f"out:{out} err:{err} rc:{rc}")


def get_local_node_id():
    node_links = uus_node_links()
    for node_link in node_links:
        local = node_link.get("local")
        if local:
            return node_link.get("node_id")


def change_sn():
    disk_sn_path = Path(DiskSnPath)
    disk_sn_path.mkdir(parents=True, exist_ok=True)

    exist_sn = []
    for file in disk_sn_path.iterdir():
        exist_sn.append(file.name)

    node_id = get_local_node_id()
    if not node_id:
        logging.error(f"not found current node_id")
        return
    disk_list = uus_disk_list()
    for disk in disk_list:
        disk_id = disk.get("id")
        sn = disk.get("sn")
        logging.debug(f"handle disk: {disk_id}")
        if not sn:
            logging.error(f"sn error: {sn}")
            continue
        if len(sn) < 20:
            logging.info(f"sn is ok: {sn}")
            # uus_disk_remove(disk_id)
            continue
        uus_disk_remove(disk_id)
        if sn in exist_sn:
            logging.info(f"sn is ok: {sn}")
            continue
        sn_file_path = disk_sn_path.joinpath(sn)
        new_sn = sn[:20]
        sn_file_path.write_text(new_sn, encoding="utf-8")
        logging.info(f"change sn {sn} ---> {new_sn}")


if __name__ == '__main__':
    change_sn()
